//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<dir_tree.h>
///	@path	~/src/lib/utilities/
///	@date	2007/09/07
///	@desc	Director tree template.

#pragma once

#include "xeres.h"

// STL
#include <vector>

#include "lib/utilities/dict.h"
#include "lib/utilities/string.h"

namespace xeres {

	/*!
		\class	dir_tree
		\brief	A generic directory access form template.
				Any components can be stored by a category like:
				'Root/Parent/Child' form, and can be access in
				the same way.
				Notice the content will be treated as a reference
				or value, not a pointer, so nothing will be freed
				while destruction.
	*/
	template< typename _Content > class dir_tree
	{
	public:

		/// \ctor
		dir_tree( void );

		/// \dtor
		~dir_tree( void );

	// methods

		/*!
			\brief		Open specific dir node from the tree.
			\return		Node content pointer.
			\param[in]	path				Node path.
			\param[in]	create_non_exist	If true, create directories
											follow the path declarations while
											directory does not exist.
		*/
		_Content * open_node( const WString& path , bool create_non_exist = false );

		/*!
			\brief		Open specific dir node from the tree.
			\return		Node content pointer.
			\param[in]	path	Node path.
		*/
		const _Content * open_node( const WString& path ) const;

		/*!
			\brief		Open specific dir node's parent from the tree.
			\return		Node's parent content pointer.
			\param[in]	path	Node path.
		*/
		const _Content * open_parent( const WString& path ) const;

		/*!
			\brief		Open specific dir node & its parent from the tree.
			\return		Node and its parent content pointer.
			\param[in]		path	Node path.
			\param[in,out]	node	Node retriever.
			\param[in,out]	parent	Parent node retriever.
		*/
		bool open_node_with_parent( const WString& path , _Content *& node , _Content *& parent );

		/*!
			\brief		Delete dir node by path.
			\return		Result of operation.
			\param[in]	path	Node path.
		*/
		bool del_node( const WString& path );

		/*!
			\brief		Delete the whole sub directory by path.
			\return		Result of operation.
			\param[in]	path	Node path.
		*/
		bool del_dir( const WString& path );

		/*!
			\brief		Clear all nodes.
		*/
		void clear( void );

		/*!
			\brief		Check if tree is empty
			\return		Is tree empty.
		*/
		bool empty( void ) const;

		/*!
			\brief		List directory names by path.
			\return		Result of operation.
			\param[in]	path	Node path.
			\param[in]	result	Directory node name list.
		*/
		bool list_dir( const WString& path , std::vector< WString >& result ) const;

		/*!
			\brief		List directory contents by path.
			\return		Result of operation.
			\param[in]	path	Node path.
			\param[in]	result	Directory content list.
		*/
		bool list_dir( const WString& path , std::vector< _Content >& result ) const;

		/*!
			\brief		List directory names & contents by path.
			\return		Result of operation.
			\param[in]	path	Node path.
			\param[in]	result	Directory names & contents map.
		*/
		bool list_dir( const WString& path , dict< WString , _Content >& result ) const;

	private:

		struct dir_node;

		struct DirIter
		{
			int												m_depth;
			dir_node *										m_parent;
			typename dict< WString , dir_node >::iterator 	m_current;

			// depth
			int depth( void ) const;

			// directory name
			const WString& name( void ) const;

			// next
			DirIter& next( void );

			// content
			_Content& content( void );

			const _Content& content( void ) const;

			// next
			DirIter& operator ++ ( void );

			// content
			_Content& operator * ( void );

			const _Content& operator * ( void ) const;

			// comparison
			bool operator == ( const DirIter& iter ) const;

			bool operator != ( const DirIter& iter ) const;
		};

	public:
		typedef DirIter iterator;

	private:

		// dir node store
		struct dir_node
		{
			// node content
			_Content					m_content;
			// parent
			dir_node *					m_parent;
			// dir name
			WString						m_name;
			// child map
			dict< WString , dir_node >	m_children;

			/// \ctor
			dir_node( void );

			// copier
			dir_node( const dir_node& rhs );

			// open directory
			dir_node * open_dir( const StringSeq& seq , int current ,
				bool create_non_exist );

			// open directory
			dir_node * open_dir( const StringSeq& seq , int current ,
				std::vector< iterator >& tree , bool create_non_exist );

			// open section
			const dir_node * open_dir( const StringSeq& seq , int current ) const;

			// delete directory
			void del_child( dir_node * child );
		};

		// root node
		dir_node			m_root;

	public:

		/*!
			\brief		Begin iterate.
			\return		Iterator of start of dir tree.
		*/
		iterator begin( void );

		/*!
			\brief		Get end iterator.
			\return		Iterator of the end of dir tree.
		*/
		iterator end( void );

		/*!
			\brief		Open specific dir node from the tree, and with parent tree.
			\return		Node content pointer.
			\param[in]		path				Node path.
			\param[in,out]	tree				Iterator list.
			\param[in]		create_non_exist	If true, create directories
												follow the path declarations while
												directory does not exist.
			
		*/
		_Content * open_node( const WString& path , std::vector< iterator >& tree , 
			bool create_non_exist = false );

		/*!
			\brief		List directory names by path.
			\return		Result of operation.
			\param[in]	node	Node iterator.
			\param[in]	result	Directory node name list.
			
		*/
		bool list_dir( const iterator& node , std::vector< WString >& result ) const;

		/*!
			\brief		List directory contents by path.
			\return		Result of operation.
			\param[in]	node	Node iterator.
			\param[in]	result	Directory content list.
			
		*/
		bool list_dir( const iterator& node , std::vector< _Content >& result ) const;

		/*!
			\brief		List directory names & contents by path.
			\return		Result of operation.
			\param[in]	node	Node iterator.
			\param[in]	result	Directory names & contents map.
			
		*/
		bool list_dir( const iterator& node , dict< WString , _Content >& result ) const;

		/*!
			\brief		List directory names by path.
			\return		Result of operation.
			\param[in]	node	Node iterator.
			\param[in]	result	Iterator list.			
		*/
		bool list_dir( const iterator& node , std::vector< iterator >& result );


		/*!
			\brief		List directory names in root dir.
			\param[in]	result	Directory node name list.
		*/
		void list_root( std::vector< WString >& result ) const;

		/*!
			\brief		List directory contents by path.
			\param[in]	result	Directory content list.
		*/
		void list_root( std::vector< _Content >& result ) const;

		/*!
			\brief		List directory names & contents by path.
			\param[in]	result	Directory names & contents map.
		*/
		void list_root( dict< WString , _Content >& result ) const;

		/*!
			\brief		List directory names by path.
			\param[in]	result	Iterator list.
		*/
		void list_root( std::vector< iterator >& result );
	};

} // namespace xeres

#include "lib/utilities/dir_tree.inl"
